In [ ]:
%%HTML
<style>
.container { width:100% }
</style>
The module Set
implements sets as
AVL trees.
The API provided by Set
offers the following functions and methods:
Set()
creates an empty set.S.isEmpty()
checks whether the set S
is empty.S.member(x)
checks whether x
is an element of the set S
.S.insert(x)
inserts x
into the set S
.
This does not return a new set but rather modifies the set S
.S.delete(x)
deletes x
from the set S
.
This does not return a new set but rather modifies the set S
.S.pop()
returns the smallest element of the set S
.
Furthermore, this element is removed from S
.
Since sets are implemented as ordered binary trees, the elements of a set need to be comparable, i.e. if x
and y
are inserted into a set, then the
expression x < y
must return a Boolean value and <
has to define
linear order.The module Set
can be used to implement a priority queue that supports the removal of elements.
In [ ]:
import Set
The function search
takes three arguments to solve a search problem:
start
is the start state of the search problem,goal
is the goal state, andnext_states
is a function with signature $\texttt{next_states}:Q \rightarrow 2^Q$, where $Q$ is the set of states.
For every state $s \in Q$, $\texttt{next_states}(s)$ is the set of states that can be reached from $s$ in one step.heuristic
is a function that takes two states as arguments. It returns an estimate of the
length of the shortest path between these states.
If successful, search
returns a path from start
to goal
that is a solution of the search problem
$$ \langle Q, \texttt{next_states}, \texttt{start}, \texttt{goal} \rangle. $$The function search
implements A$^*$ search.
In [ ]:
def search(start, goal, next_states, heuristic):
Parent = { start:start }
Distance = { start: 0 }
estGoal = heuristic(start, goal)
Estimate = { start: estGoal }
Frontier = Set.Set()
Frontier.insert( (estGoal, start) )
while not Frontier.isEmpty():
estimate, state = Frontier.pop()
if state == goal:
print(len(Estimate))
return path_to(state, Parent)
stateDist = Distance[state]
for ns in next_states(state):
oldEstimate = Estimate.get(ns, None)
newEstimate = stateDist + 1 + heuristic(ns, goal)
if oldEstimate == None or newEstimate < oldEstimate:
Distance[ns] = stateDist + 1
Estimate[ns] = newEstimate
Parent[ns] = state
Frontier.insert( (newEstimate, ns) )
if oldEstimate != None:
Frontier.delete( (oldEstimate, ns) )
Given a state
and a parent dictionary Parent
, the function path_to
returns a path leading to the given state
.
In [ ]:
def path_to(state, Parent):
p = Parent[state]
if p == state:
return [state]
return path_to(p, Parent) + [state]
Lets draw the start state and animate the solution that has been found.
In [ ]:
%run Sliding-Puzzle.ipynb
In [ ]:
%%time
Path = search(start, goal, next_states, manhattan)
print(len(Path)-1)
In [ ]:
animation(Path)
In [ ]: